package com.icloud.article.boot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icloud.article.boot.dto.AttentionPageDto;
import com.icloud.article.boot.service.AttentionService;
import com.icloud.article.boot.vo.AttentionVo;
import com.icloud.common.cache.constants.CacheConstants;
import com.icloud.common.cache.service.RedisService;
import com.icloud.common.core.api.ResultCode;
import com.icloud.common.database.mapper.AppCustomerMapper;
import com.icloud.common.database.mapper.AttentionMapper;
import com.icloud.common.database.model.AppCustomer;
import com.icloud.common.database.model.Attention;
import com.icloud.common.web.enums.StateEnum;
import com.icloud.common.web.exception.Asserts;
import com.icloud.common.web.util.AuthUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 关注service 实现类
 */

@Service
public class AttentionServiceImpl extends ServiceImpl<AttentionMapper, Attention> implements AttentionService {
    @Autowired
    private AppCustomerMapper appCustomerMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private AuthUtil authUtil;
    /**
     * 关注
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean attention(Long customerId) {
        Long loginId = authUtil.getUserId();
        // 自己不能关注自己
        Asserts.fail(loginId.equals(customerId), ResultCode.VALIDATE_FAILED);

        long count = count(new LambdaQueryWrapper<Attention>()
                .eq(Attention::getCreatedId, loginId)
                .eq(Attention::getFollowedId, customerId));
        if(count>0){
            return true;
        }

        Attention attention = new Attention();
        attention.setCreatedId(loginId);
        attention.setFollowedId(customerId);
        save(attention);
        return true;
    }


    /**
     * 取消关注
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean cancel(Long customerId) {
        Long loginId = authUtil.getUserId();

        Attention attention = baseMapper.selectOne(new LambdaQueryWrapper<Attention>()
                .eq(Attention::getCreatedId, loginId)
                .eq(Attention::getFollowedId, customerId));
        if(attention==null){
            return true;
        }

        baseMapper.deleteById(attention);
        return true;
    }


    /**
     * 关注列表
     * @param dto
     * @return
     */
    @Override
    public IPage<AttentionVo> attentionPage(AttentionPageDto dto) {
        Long loginId = authUtil.getUserId();
        Long customerId = dto.getCustomerId();

        IPage<Attention> attentionPage = page(new Page<>(dto.getCurrent(),dto.getPageSize()),new LambdaQueryWrapper<Attention>()
                .eq(Attention::getCreatedId, customerId));
        List<Attention> attList = attentionPage.getRecords();

        IPage<AttentionVo> result = new Page();
        result.setTotal(attentionPage.getTotal());
        if(CollectionUtils.isEmpty(attList)){
            return result;
        }

        List<Long> followedIdList = attList.stream().map(Attention::getFollowedId).collect(Collectors.toList());
        List<AppCustomer> customerList = appCustomerMapper.selectList(new LambdaQueryWrapper<AppCustomer>()
                .in(AppCustomer::getId, followedIdList)
                .eq(AppCustomer::getState, StateEnum.NORMAL.getCode()
                ));
        Map<Long, AppCustomer> customerMap = customerList.stream().collect(Collectors.toMap(AppCustomer::getId, Function.identity()));

        // 相互关注
        List<Attention> eachList = list(new LambdaQueryWrapper<Attention>()
                .eq(Attention::getFollowedId, customerId)
                .in(Attention::getCreatedId, followedIdList)
        );
        List<Long> eachIdList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(eachList)){
            List<Long> tmpEachIdList = eachList.stream().map(Attention::getCreatedId).collect(Collectors.toList());
            eachIdList.addAll(tmpEachIdList);
        }

        List<AttentionVo> voList = attList.stream().map(att->{
            AttentionVo vo = new AttentionVo();
            BeanUtils.copyProperties(att, vo);

            Long followedId = att.getFollowedId();
            AppCustomer followed = customerMap.get(followedId);
            if(followed!=null){
                vo.setNickname(followed.getNickname());
                vo.setAvatarUrl(followed.getAvatarUrl());
            }
            if(!CollectionUtils.isEmpty(eachIdList) && eachIdList.contains(followedId)){
                vo.setFollowedOnEach(true);
            }

            String key = CacheConstants.CACHE_ACTIVE_USER + followedId;
            Object cachedActiveTimeObj = redisService.get(key);
            Long cachedActiveTime = 0L;
            if(cachedActiveTimeObj instanceof Integer){
                cachedActiveTime = ((Integer)cachedActiveTimeObj).longValue();
            }
            if(cachedActiveTimeObj instanceof Long){
                cachedActiveTime = (Long)cachedActiveTimeObj;
            }
            vo.setLastAccessTime(cachedActiveTime);
            return vo;
        }).collect(Collectors.toList());
        result.setRecords(voList);
        return result;
    }


    /**
     * 粉丝列表
     * @param dto
     * @return
     */
    @Override
    public IPage<AttentionVo> fansPage(AttentionPageDto dto) {
        Long loginId = authUtil.getUserId();
        Long customerId = dto.getCustomerId();

        IPage<Attention> fansPage = page(new Page<>(dto.getCurrent(),dto.getPageSize()),new LambdaQueryWrapper<Attention>()
                .eq(Attention::getFollowedId, customerId));
        List<Attention> fansList = fansPage.getRecords();

        IPage<AttentionVo> result = new Page();
        result.setTotal(fansPage.getTotal());
        if(CollectionUtils.isEmpty(fansList)){
            return result;
        }

        List<Long> fansIdList = fansList.stream().map(Attention::getCreatedId).collect(Collectors.toList());
        List<AppCustomer> customerList = appCustomerMapper.selectList(new LambdaQueryWrapper<AppCustomer>()
                .in(AppCustomer::getId, fansIdList)
                .eq(AppCustomer::getState, StateEnum.NORMAL.getCode()
                ));
        Map<Long, AppCustomer> customerMap = customerList.stream().collect(Collectors.toMap(AppCustomer::getId, Function.identity()));

        // 相互关注
        List<Attention> eachList = list(new LambdaQueryWrapper<Attention>()
                .eq(Attention::getCreatedId, customerId)
                .in(Attention::getFollowedId, fansIdList)
        );
        List<Long> eachIdList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(eachList)){
            List<Long> tmpEachIdList = eachList.stream().map(Attention::getFollowedId).collect(Collectors.toList());
            eachIdList.addAll(tmpEachIdList);
        }

        List<AttentionVo> voList = fansList.stream().map(f->{
            AttentionVo vo = new AttentionVo();
            BeanUtils.copyProperties(f, vo);

            Long fansId = f.getCreatedId();
            AppCustomer fans = customerMap.get(fansId);
            if(fans!=null){
                vo.setNickname(fans.getNickname());
                vo.setAvatarUrl(fans.getAvatarUrl());
            }
            if(!CollectionUtils.isEmpty(eachIdList) && eachIdList.contains(fansId)){
                vo.setFollowedOnEach(true);
            }

            String key = CacheConstants.CACHE_ACTIVE_USER + fansId;
            Object cachedActiveTimeObj = redisService.get(key);
            Long cachedActiveTime = 0L;
            if(cachedActiveTimeObj instanceof Integer){
                cachedActiveTime = ((Integer)cachedActiveTimeObj).longValue();
            }
            if(cachedActiveTimeObj instanceof Long){
                cachedActiveTime = (Long)cachedActiveTimeObj;
            }
            vo.setLastAccessTime(cachedActiveTime);
            return vo;
        }).collect(Collectors.toList());
        result.setRecords(voList);
        return result;
    }
}
